package org.alanlau.eureka.controller;

import com.netflix.appinfo.AmazonInfo;
import com.netflix.appinfo.AmazonInfo.MetaDataKey;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.DataCenterInfo.Name;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Pair;
import com.netflix.eureka.EurekaServerContextHolder;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.resources.StatusResource;
import com.netflix.eureka.util.StatusInfo;
import com.netflix.eureka.util.StatusInfo.Builder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.eureka.server.EurekaController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;

/**
 * 自定义的Eureka dashboard
 * @author liukun
 * @date  2019/12/5 10:02
 * @version 1.0
 */
@Controller
@RequestMapping({"${eureka.dashboard.path:/}"})
public class EurekaServerController extends EurekaController {
    @Value("${eureka.dashboard.path:/}")
    private String dashboardPath = "";

    public EurekaServerController(ApplicationInfoManager applicationInfoManager) {
        super(applicationInfoManager);
    }

    @Override
    @RequestMapping(method = {RequestMethod.GET})
    public String status(HttpServletRequest request, Map<String, Object> model) {
        this.populateBase(request, model);
        this.populateApps(model);

        StatusInfo statusInfo;
        try {
            statusInfo = (new StatusResource()).getStatusInfo();
        } catch (Exception var5) {
            statusInfo = Builder.newBuilder().isHealthy(false).build();
        }

        model.put("statusInfo", statusInfo);
        this.populateInstanceInfo(model, statusInfo);
        this.filterReplicas(model, statusInfo);
        return "eureka/status";
    }

    private PeerAwareInstanceRegistry getRegistry() {
        return EurekaServerContextHolder.getInstance().getServerContext().getRegistry();
    }

    private void populateApps(Map<String, Object> model) {
        List<Application> sortedApplications = this.getRegistry().getSortedApplications();
        ArrayList<Map<String, Object>> apps = new ArrayList();
        Iterator var4 = sortedApplications.iterator();

        while(var4.hasNext()) {
            Application app = (Application)var4.next();
            LinkedHashMap<String, Object> appData = new LinkedHashMap();
            apps.add(appData);
            appData.put("name", app.getName());
            Map<String, Integer> amiCounts = new HashMap();
            Map<InstanceStatus, List<Pair<String, String>>> instancesByStatus = new HashMap();
            Map<String, Integer> zoneCounts = new HashMap();
            Iterator var10 = app.getInstances().iterator();

            InstanceStatus status;
            while(var10.hasNext()) {
                InstanceInfo info = (InstanceInfo)var10.next();
                String serviceVersion = info.getMetadata().get("version");
                String id = info.getId();
                if (serviceVersion != null && serviceVersion.length() > 0) {
                    id = String.format("%s(%s)", id, serviceVersion);
                }
                String url = info.getStatusPageUrl();
                status = info.getStatus();
                String ami = "n/a";
                String zone = "";
                if (info.getDataCenterInfo().getName() == Name.Amazon) {
                    AmazonInfo dcInfo = (AmazonInfo)info.getDataCenterInfo();
                    ami = dcInfo.get(MetaDataKey.amiId);
                    zone = dcInfo.get(MetaDataKey.availabilityZone);
                }

                Integer count = (Integer)amiCounts.get(ami);
                if (count != null) {
                    amiCounts.put(ami, count + 1);
                } else {
                    amiCounts.put(ami, 1);
                }

                count = (Integer)zoneCounts.get(zone);
                if (count != null) {
                    zoneCounts.put(zone, count + 1);
                } else {
                    zoneCounts.put(zone, 1);
                }

                List<Pair<String, String>> list = (List)instancesByStatus.computeIfAbsent(status, (k) -> {
                    return new ArrayList();
                });
                list.add(new Pair(id, url));
            }

            appData.put("amiCounts", amiCounts.entrySet());
            appData.put("zoneCounts", zoneCounts.entrySet());
            ArrayList<Map<String, Object>> instanceInfos = new ArrayList();
            appData.put("instanceInfos", instanceInfos);
            Iterator var23 = instancesByStatus.entrySet().iterator();

            while(var23.hasNext()) {
                Entry<InstanceStatus, List<Pair<String, String>>> entry = (Entry)var23.next();
                List<Pair<String, String>> value = (List)entry.getValue();
                status = (InstanceStatus)entry.getKey();
                LinkedHashMap<String, Object> instanceData = new LinkedHashMap();
                instanceInfos.add(instanceData);
                instanceData.put("status", entry.getKey());
                ArrayList<Map<String, Object>> instances = new ArrayList();
                instanceData.put("instances", instances);
                instanceData.put("isNotUp", status != InstanceStatus.UP);
                Iterator var29 = value.iterator();

                while(var29.hasNext()) {
                    Pair<String, String> p = (Pair)var29.next();
                    LinkedHashMap<String, Object> instance = new LinkedHashMap();
                    instances.add(instance);
                    instance.put("id", p.first());
                    String url = (String)p.second();
                    instance.put("url", url);
                    boolean isHref = url != null && url.startsWith("http");
                    instance.put("isHref", isHref);
                }
            }
        }

        model.put("apps", apps);
    }

    private void populateInstanceInfo(Map<String, Object> model, StatusInfo statusInfo) {
        InstanceInfo instanceInfo = statusInfo.getInstanceInfo();
        Map<String, String> instanceMap = new HashMap();
        instanceMap.put("ipAddr", instanceInfo.getIPAddr());
        instanceMap.put("status", instanceInfo.getStatus().toString());
        if (instanceInfo.getDataCenterInfo().getName() == Name.Amazon) {
            AmazonInfo info = (AmazonInfo)instanceInfo.getDataCenterInfo();
            instanceMap.put("availability-zone", info.get(MetaDataKey.availabilityZone));
            instanceMap.put("public-ipv4", info.get(MetaDataKey.publicIpv4));
            instanceMap.put("instance-id", info.get(MetaDataKey.instanceId));
            instanceMap.put("public-hostname", info.get(MetaDataKey.publicHostname));
            instanceMap.put("ami-id", info.get(MetaDataKey.amiId));
            instanceMap.put("instance-type", info.get(MetaDataKey.instanceType));
        }

        model.put("instanceInfo", instanceMap);
    }
}